package com.reyco1.medusa.loading
{
	import com.reyco1.medusa.abstract.SmartEventDispatcher;
	import com.reyco1.medusa.events.LoaderEvent;
	import com.reyco1.medusa.util.MathUtil;
	
	import flash.events.Event;
	import flash.events.HTTPStatusEvent;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	public class DataLoader extends SmartEventDispatcher implements ILoader
	{
		protected var _content:*;
		protected var _loaderObject:Object;
		private var internalLoader:URLLoader;
		private var internalRequest:URLRequest;
		
		private var onComplete:Function;
		private var onProgress:Function;
		private var onError:Function;
		
		public function DataLoader(request:URLRequest, loaderObj:Object = null)
		{
			super();
			
			internalRequest = request;
			
			if(loaderObj)
			{
				loaderObject = loaderObj;
			}
		}
		
		public function load():void
		{			
			try 
			{
				internalLoader = new URLLoader();
				configureListeners(internalLoader);
				internalLoader.load(internalRequest);
			} catch (error:Error) {
				log("Unable to load requested document.");
			}
		}		
		
		public function clear():void
		{
			removeListeners(internalLoader);
			removeAllListeners();
			internalLoader.close();
			internalLoader = null;
		}
		
		public function destroy():void
		{
			clear();
		}
		
		/* private */
		
		private function configureListeners(dispatcher:IEventDispatcher):void 
		{
			dispatcher.addEventListener(Event.COMPLETE, completeHandler);
			dispatcher.addEventListener(Event.OPEN, openHandler);
			dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
			dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
			dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
		}
		
		private function removeListeners(dispatcher:IEventDispatcher):void 
		{
			dispatcher.addEventListener(Event.COMPLETE, completeHandler);
			dispatcher.addEventListener(Event.OPEN, openHandler);
			dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
			dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
			dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
		}
		
		/* handlers */
		
		protected function completeHandler(event:Event):void 
		{
			_content = internalLoader.data;
			
			var e:LoaderEvent = new LoaderEvent(LoaderEvent.COMPLETE, _content);
			dispatchEvent(e);
			
			if(onComplete != null) onComplete(_content);
		}
		
		protected function openHandler(event:Event):void 
		{
			var e:LoaderEvent = new LoaderEvent(LoaderEvent.OPEN);
			dispatchEvent(e);
		}
		
		protected function progressHandler(event:ProgressEvent):void 
		{
			var e:LoaderEvent = new LoaderEvent(LoaderEvent.PROGRESS, {bytesLoaded:event.bytesLoaded, bytesTotal:event.bytesTotal});
			dispatchEvent(e);
			
			var percent:Number = MathUtil.percentage(event.bytesLoaded, event.bytesTotal);
			
			if(onProgress != null) onProgress({bytesLoaded:event.bytesLoaded, bytesTotal:event.bytesTotal, percent:percent});
		}
		
		protected function securityErrorHandler(event:SecurityErrorEvent):void 
		{
			var e:LoaderEvent = new LoaderEvent(LoaderEvent.SECURITY_ERROR, event.text);
			dispatchEvent(e);
		}
		
		protected function httpStatusHandler(event:HTTPStatusEvent):void 
		{
			var e:LoaderEvent = new LoaderEvent(LoaderEvent.HTTP_STATUS, event.status);
			dispatchEvent(e);
		}
		
		protected function ioErrorHandler(event:IOErrorEvent):void 
		{
			var e:LoaderEvent = new LoaderEvent(LoaderEvent.IO_ERROR, event.text);
			dispatchEvent(e);
			
			if(onError != null) onError(event.text);
		}
		
		/* properties */
		
		public function get content():*
		{
			return _content;
		}

		public function get loaderObject():Object
		{
			return _loaderObject;
		}

		public function set loaderObject(value:Object):void
		{
			_loaderObject = value;
			
			onComplete = loaderObject.onComplete;
			onProgress = loaderObject.onProgress;
			onError    = loaderObject.onError;
		}

	}
}